/*
* @Author: Jimmy
* @LastModifiedBy: Jimmy
* @Date: 2024-05-25 17:25:04
 * @LastEditTime: 2024-09-14 18:43:13
 * @FilePath: /nest_study/server/src/modules/system/role/role.service.ts
*/
import { Injectable } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { CreateRoleDto, DeleteRolerDto, findRoleDto, ListRoleDto, UpdateRoleDto } from './dto/index.dto';
import { SystemRoleEntity } from './entities/role.entity';
import { EntityManager, getManager, In, Repository } from 'typeorm';
import { ResultData } from 'src/common/utils/result';
import { SystemMenuEntity } from '../menu/entities/menu.entity';
import { SystemUserEntity } from '../user/entities/user.entity';
import { ListToTree } from 'src/common/utils';
import { UpdateMenuDto } from '../menu/dto/index.dto';
import { CacheService } from 'src/modules/cache/cache.service';
import { LOGIN_TOKEN_EXPIRESIN } from 'src/common/constant';
import { MenuService } from '../menu/menu.service';

@Injectable()
export class RoleService {
  constructor(
    @InjectRepository(SystemUserEntity)
    private readonly userRepo: Repository<SystemUserEntity>,
    @InjectRepository(SystemRoleEntity)
    private readonly roleRepo: Repository<SystemRoleEntity>,
    @InjectRepository(SystemMenuEntity)
    private readonly menuRepo: Repository<SystemMenuEntity>,
    @InjectEntityManager()
    private readonly entityManager: EntityManager,
    private readonly cacheService: CacheService,
    private readonly menuService: MenuService,
  ) { }

  async create(createRoleDto: CreateRoleDto) {
    let { name, menuIds = [] } = createRoleDto;
    let entity = this.roleRepo.createQueryBuilder('role');
    entity.where({
      name
    });
    let data = await entity.getOne();
    if (data) {
      return ResultData.fail(500, '角色已存在');
    }
    let list = [];//用户保存拥有的菜单
    if (menuIds.length) {
      list = await this.menuRepo.findBy({ id: In(menuIds || []) });
      if (list.length != menuIds.length) {
        return ResultData.fail(500, '部分菜单不存在');
      }
    }
    createRoleDto.menus = list;
    let res = await this.roleRepo.save(createRoleDto);
    await this.findAllAndCache();
    return ResultData.ok(res);
  }

  //获取角色权限
  async findAuth(user: any) {
    let roles = [...user.roles];
    if (roles.length == 0) {
      return ResultData.ok([]);
    }
    let userRoleIds = [];
    let userAllMenuIds = [];

    let userRoles = await this.cacheService.storeGet(`user_${user.id}_roleIds`)
    if (userRoles?.length) {
      userRoleIds = [...userRoles];
    } else {
      let findUser = await this.userRepo.createQueryBuilder('user').where({
        id: user.id
      }).getOne();
      userRoleIds = [...findUser.roleIds];
    }
    if (!userRoleIds?.length) {
      return ResultData.fail(500, '信息错误');
    } else {
      await this.findAllAndCache();
    }

    let sysRoles = await this.cacheService.storeGet('sys_roles');
    if (sysRoles?.length) {
      sysRoles.map(role => {
        if (userRoleIds.indexOf(role.id) >= 0) {
          userAllMenuIds = [...userAllMenuIds, ...role.menuIds];
        }
      })
    } else {
      const roles = await this.roleRepo.findBy({ id: In(userRoleIds || []) });
      roles.map(role => {
        userAllMenuIds = [...userAllMenuIds, ...role.menuIds]
      })
    }

    let menuIds = [...new Set(userAllMenuIds)];
    let menuData = [];
    let sysMenus = await this.cacheService.storeGet('sys_menus');
    if (sysMenus?.length) {
      sysMenus.map(menu => {
        if (menuIds.indexOf(menu.id)>=0) {
          menuData = [...menuData, {...menu}];
        }
      })
    } else {
      menuData = await this.menuRepo.findBy({ id: In(menuIds) });
      this.menuService.findAllAndCache();
    }
    const treeData = ListToTree(menuData, (m: UpdateMenuDto) => m.id, (m: UpdateMenuDto) => m.name);
    return ResultData.ok(treeData);
  }

  async query(query: ListRoleDto) {
    let entity = this.roleRepo.createQueryBuilder('role');
    if (query.name) {
      entity.andWhere(`role.name LIKE "%${query.name}%"`);
    }
    if (query.showMenu == 0) {
      entity.leftJoinAndSelect('role.menus', 'menu');
    }
    entity.skip(query.size * (query.page - 1)).take(query.size);
    const [list, total] = await entity.getManyAndCount();
    return ResultData.ok({
      list: list,
      total,
      size: query.size,
      page: query.page
    })
  }

  async findOne(query: findRoleDto) {
    let { id } = query;
    let entity = this.roleRepo.createQueryBuilder('role');
    entity.where({
      id
    })
    entity.leftJoinAndSelect('role.menus', 'menu');
    let data = await entity.getOne();
    if (!data) {
      return ResultData.fail(500, '未查询到信息');
    } else {
      return ResultData.ok({
        ...data
      })
    }
  }

  async update(updateRoleDto: UpdateRoleDto) {
    let { id, menuIds = [], name } = updateRoleDto;
    if (!id) {
      return ResultData.fail(500, '参数错误');
    }
    let result = await this.roleRepo.findOne({
      where: { name }
    });
    if (result && result?.id != id) {
      return ResultData.fail(500, '角色名称已存在')
    }
    let data = await this.roleRepo.findOne({
      where: { id }
    });
    if (!data) {
      return ResultData.fail(500, '更新信息不存在');
    }
    let list = [];//用户保存拥有的菜单
    if (menuIds.length) {
      list = await this.menuRepo.findBy({ id: In(menuIds || []) });
      if (list.length != menuIds.length) {
        return ResultData.fail(500, '部分菜单不存在');
      }
    }
    updateRoleDto.menus = list;
    await this.removeRelationInfo([id]);
    await this.findAllAndCache();
    await this.roleRepo.save(updateRoleDto);
    return ResultData.ok("更新成功");
  }

  async remove(roleInfo: DeleteRolerDto) {
    let { ids } = roleInfo;
    if (!ids || ids.length === 0) {
      return ResultData.fail(500, '参数错误');
    }
    let total = 0;
    for (let i = 0; i < ids.length; i++) {
      let id = ids[i];
      let entity = this.userRepo.createQueryBuilder('user');
      entity.where("JSON_CONTAINS(user.roleIds,:roleId)", { roleId: id.toString() });
      const num = await entity.getCount();
      total += num;
    }
    if (total > 0) {
      return ResultData.fail(500, '角色正在被使用');
    }
    await this.roleRepo.delete(ids);
    await this.findAllAndCache();
    await this.removeRelationInfo(roleInfo.ids)
    return ResultData.ok();
  }

  //删除关联表信息
  async removeRelationInfo(roleIds: number[]) {
    // 使用 QueryBuilder 构建 DELETE 语句  
    await this.entityManager.createQueryBuilder()
      .delete()
      .from('sys_role_menu') // 关联表名  
      .where('role_id IN (:...roleIds)', { roleIds }) // 根据 roleId 过滤  
      // .andWhere('menu_id IN (:...menuIds)', { menuIds }) // 根据 menuIds 过滤  
      .execute();
  }

  //查询全部角色信息并缓存
  async findAllAndCache() {
    let entity = this.roleRepo.createQueryBuilder('role');
    const [list] = await entity.getManyAndCount();
    this.cacheService.storeSet('sys_roles', list, LOGIN_TOKEN_EXPIRESIN)
  }
}
